#
# A simple 2D vector class
#

import math

class Vector(object):
    'Represents a 2D vector'

    # Optimisation
    __slots__ = ('x','y')
    def __init__(self, x=0, y=None):
        self.x = x
        if y is None: self.y = self.x
        else: self.y = y
        
    def __add__(self, val):
        return Vector(self.x+val[0], self.y+val[1])
    def __sub__(self, val):
        return Vector(self.x-val[0], self.y-val[1])
    def __iadd__(self, val):
        self.x += val[0]
        self.y += val[1]
        return self
    def __isub__(self, val):
        self.x -= val[0]
        self.y -= val[1]
        return self
    def __div__(self, val):
        inv = 1.0 / val
        return Vector(self.x*inv, self.y*inv)
    def __mul__(self, val):
        return Vector(self.x*val, self.y*val)
    def __idiv__(self, val):
        inv = 1.0 / val
        self.x *= inv
        self.y *= inv
        return self
    def __imul__(self, val):
        self[0] *= val
        self[1] *= val
        return self
    def __getitem__(self, key):
        if( key == 0):
            return self.x
        elif( key == 1):
            return self.y
        else:
            raise Exception("Invalid key to Point")
    def __setitem__(self, key, value):
        if( key == 0):
            self.x = value
        elif( key == 1):
            self.y = value
        else:
            raise Exception("Invalid key to Point")
    def __str__(self):
        return "(" + str(self.x) + "," + str(self.y) + ")"
    def as_tuple(self):
        return (self.x, self.y)
    def clone(self):
        return Vector(self.x, self.y)

def length2(vec):
    return vec[0]*vec[0] + vec[1]*vec[1]
def length(vec):
    return math.sqrt(vec[0]*vec[0] + vec[1]*vec[1])
def direction(vec):
    'Returns a new vector that has the same direction as vec, but a length of one'
    return vec / length(vec)
def dot(a, b):
    'Computes the dot product of a and b'
    return a[0]*b[0] + a[1]*b[1]
def cross(a, b):
    'Computes the 2D cross product of a and b'
    return a[0]*b[1] - a[1]*b[0]
def normal(vec):
    'Computes the normal vector to vec'
    return Vector(vec[1], -vec[0])
def angle(vec):
    'Computes the angle in radians of a vector'
    return math.atan2(vec[1], vec[0])
def project_onto(w, v):
    'Projects w onto v'
    return v * dot(w,v) / length2(v)
